package nl.cwi.arne.ui.parts;

import java.util.HashMap;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import nl.cwi.arne.Network;
import nl.cwi.arne.NetworkActivation;
import nl.cwi.arne.Node;
import nl.cwi.arne.factory.ArnePackage;

public class ActivationsTableSynchronizer extends HashMap<Node,TableColumn> {
	
	// Default serial ID:
	private static final long serialVersionUID = 1L;
	
	// Network to be monitored:
	private Network network;

	// Table that should be synchronized:
	private Table table;
	
	/**
	 * Default constructor.
	 * @param network Network to be monitored.
	 * @param table Table to be synchronized.
	 */
	public ActivationsTableSynchronizer(Network network, Table table) {
		
		this.network = network;
		this.table = table;
		
		// Register the call back listener:
		table.addListener(SWT.SetData, callbackListener);
		
		// Index column:
		TableColumn indexCol = new TableColumn(table, SWT.LEFT, 0);
		indexCol.setWidth(35);
		indexCol.setText("#");
		
		// Add node columns:
		network.eAdapters().add(networkListener);
		for (int i=0; i<network.getNodes().size(); i++) {
			addNode(network.getNodes().get(i),i+1);
		}
		table.setItemCount(network.getActivations().size());
		
	}
	
	@Override
	public TableColumn remove(Object object) {
		TableColumn column = super.remove(object);
		if (column!=null) column.dispose();
		return column;
	}
	
	public void dispose() {
		network.eAdapters().remove(networkListener);
		for (Node node : network.getNodes()) {
			node.eAdapters().remove(nodeListener);
			remove(node);
		}
		clear();
		if (!table.isDisposed()) {
			for (TableColumn column : table.getColumns()) {
				column.dispose();
			}
			table.clearAll();
			table.setItemCount(0);
			table.removeListener(SWT.SetData, callbackListener);
		}
	}
	
	private void addNode(Node node, int index) {
		TableColumn column = new TableColumn(table, SWT.LEFT, index);
		column.setWidth(125);
		put(node,column);
		updateColumn(node);
		node.eAdapters().add(nodeListener);
	}
	
	private void updateColumn(Node node) {
		get(node).setText(node.getName()!=null ? node.getName() : "unnamed");
	}

	// Network adapter:
	private Adapter networkListener = new AdapterImpl() {
		@Override
		public void notifyChanged(Notification event) {
			int feature = event.getFeatureID(Network.class);
			if (feature==ArnePackage.NETWORK__NODES) {
				int type = event.getEventType();
				if (type==Notification.ADD) {
					addNode((Node) event.getNewValue(), event.getPosition()+1);
				} else if (type==Notification.REMOVE) {
					remove(event.getOldValue());
				}
			}
			else if (feature==ArnePackage.NETWORK__ACTIVATIONS) {
				Display.getDefault().asyncExec(new Runnable() {
					public void run() {
						table.setItemCount(network.getActivations().size());
					}
				});
			}
		}
	};
	
	// Node adapter:
	private Adapter nodeListener = new AdapterImpl() {
		@Override
		public void notifyChanged(Notification event) {
			updateColumn((Node) event.getNotifier());
		}
	};
	
	// Table call-back listener:
	private Listener callbackListener = new Listener() {
		public void handleEvent(Event event) {
			TableItem item = (TableItem) event.item;
			int row = table.indexOf(item);
			item.setText(0,String.valueOf(row+1));
			NetworkActivation activation = network.getActivations().get(row);
			for (int i=0; i<network.getNodes().size(); i++) {
				Node node = network.getNodes().get(i);
				item.setText(i+1, activation.getNodeActivation(node).toString());
			}
		}
	};
	
}
